#ifndef CSUPBR_CAMERA_H
#define CSUPBR_CAMERA_H

#include "transform.h"

namespace csupbr {

    struct CameraSample {
        CameraSample(Vec2f uv, Vec2f lens = {.0f}, float t = .0f)
            : uv(uv), lens(lens), t(t) {}

        Vec2f uv, lens;
        float t;
    };

    struct Camera {
        virtual Ray genRay(const CameraSample &cs) const = 0;
    };

    struct PerspectiveCamera : Camera {
        // foV is Rad degree
        PerspectiveCamera(const Point3f &lookFrom, const Point3f &lookAt,
                          float foV, float aspect)
            : foV(foV), aspect(aspect), lookFrom(lookFrom) {
            Vec3f front = lookAt - lookFrom;
            Vec3f right = normalize(cross(front, {.0f, 1.f, .0f}));
            Vec3f up = normalize(cross(right, front));
            float h = std::tan(foV * .5f) * front.length();
            horizontal = 2.f * h * aspect * right;
            vertical = 2.f * h * up;
            left_bottom = lookAt - (vertical + horizontal) * .5f;
        }

        inline Ray genRay(const CameraSample &cs) const override {
            auto uv = cs.uv + cs.lens;
            Ray ret{lookFrom, normalize(left_bottom +
                                        uv.x * horizontal +
                                        uv.y * vertical -
                                        lookFrom)};
            return ret;
        }

        float foV, aspect;
        Point3f lookFrom, left_bottom;
        Vec3f horizontal, vertical;
    };

}

#endif // !CSUPBR_CAMERA_H